commit
a27e4debe9
@ -8,5 +8,6 @@ namespace MLAPI
|
|||||||
public int ClientId;
|
public int ClientId;
|
||||||
public GameObject PlayerObject;
|
public GameObject PlayerObject;
|
||||||
public List<NetworkedObject> OwnedObjects = new List<NetworkedObject>();
|
public List<NetworkedObject> OwnedObjects = new List<NetworkedObject>();
|
||||||
|
public byte[] AesKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ namespace MLAPI
|
|||||||
public List<string> MessageTypes = new List<string>();
|
public List<string> MessageTypes = new List<string>();
|
||||||
public List<string> PassthroughMessageTypes = new List<string>();
|
public List<string> PassthroughMessageTypes = new List<string>();
|
||||||
internal HashSet<ushort> RegisteredPassthroughMessageTypes = new HashSet<ushort>();
|
internal HashSet<ushort> RegisteredPassthroughMessageTypes = new HashSet<ushort>();
|
||||||
|
public HashSet<int> EncryptedChannels = new HashSet<int>();
|
||||||
public List<string> RegisteredScenes = new List<string>();
|
public List<string> RegisteredScenes = new List<string>();
|
||||||
public int MessageBufferSize = 65535;
|
public int MessageBufferSize = 65535;
|
||||||
public int ReceiveTickrate = 64;
|
public int ReceiveTickrate = 64;
|
||||||
@ -28,11 +29,12 @@ namespace MLAPI
|
|||||||
public byte[] ConnectionData = new byte[0];
|
public byte[] ConnectionData = new byte[0];
|
||||||
public float SecondsHistory = 5;
|
public float SecondsHistory = 5;
|
||||||
public bool HandleObjectSpawning = true;
|
public bool HandleObjectSpawning = true;
|
||||||
//TODO
|
|
||||||
public bool CompressMessages = false;
|
public bool EnableEncryption = true;
|
||||||
//Should only be used for dedicated servers and will require the servers RSA keypair being hard coded into clients in order to exchange a AES key
|
public bool SignKeyExchange = true;
|
||||||
//TODO
|
public string RSAPrivateKey = "<RSAKeyValue><Modulus>vBEvOQki/EftWOgwh4G8/nFRvcDJLylc8P7Dhz5m/hpkkNtAMzizNKYUrGbs7sYWlEuMYBOWrzkIDGOMoOsYc9uCi+8EcmNoHDlIhK5yNfZUexYBF551VbvZ625LSBR7kmBxkyo4IPuA09fYCHeUFm3prt4h6aTD0Hjc7ZsJHUU=</Modulus><Exponent>EQ==</Exponent><P>ydgcrq5qLJOdDQibD3m9+o3/dkKoFeCC110dnMgdpEteCruyBdL0zjGKKvjjgy3XTSSp43EN591NiXaBp0JtDw==</P><Q>7obHrUnUCsSHUsIJ7+JOrupcGrQ0XaYcQ+Uwb2v7d2YUzwZ46U4gI9snfD2J0tc3DGEh3v3G0Q8q7bxEe3H4aw==</Q><DP>L34k3c6vkgSdbHp+1nb/hj+HZx6+I0PijQbZyolwYuSOmR0a1DGjA1bzVWe9D86NAxevgM9OkOjG8yrxVIgZqQ==</DP><DQ>OB+2gyBuIKa2bdNNodrlVlVC2RtXnZB/HwjAGjeGdnJfP8VJoE6eJo3rLEq3BG7fxq1xYaUfuLhGVg4uOyngGQ==</DQ><InverseQ>o97PimYu58qH5eFmySRCIsyhBr/tK2GM17Zd9QQPJZRSorrhIJn1m6gwQ/G5aJLIM/3Yl04CoyqmQGsPXMzW2w==</InverseQ><D>CxAR1i22w4vCquB7U0Pd8Nl9R2Wxez6rHTwpnoszPB+rkAzlqKj7e5FMgpykhoQfciKPyWqQZKkAeTMIRbN56JinvpAt5POId/28HDd5xjGymHE81k3RzoHqzQXFIOF1TSYKUWzjPPF/TU4nn7auD4i6lOODATsMqtLr5DRBN/0=</D></RSAKeyValue>"; //CHANGE THESE FOR PRODUCTION!
|
||||||
public bool EncryptMessages = false;
|
public string RSAPublicKey = "<RSAKeyValue><Modulus>vBEvOQki/EftWOgwh4G8/nFRvcDJLylc8P7Dhz5m/hpkkNtAMzizNKYUrGbs7sYWlEuMYBOWrzkIDGOMoOsYc9uCi+8EcmNoHDlIhK5yNfZUexYBF551VbvZ625LSBR7kmBxkyo4IPuA09fYCHeUFm3prt4h6aTD0Hjc7ZsJHUU=</Modulus><Exponent>EQ==</Exponent></RSAKeyValue>"; //CHANGE THESE FOR PRODUCTION!
|
||||||
|
|
||||||
public bool AllowPassthroughMessages = true;
|
public bool AllowPassthroughMessages = true;
|
||||||
public bool EnableSceneSwitching = false;
|
public bool EnableSceneSwitching = false;
|
||||||
|
|
||||||
@ -72,8 +74,7 @@ namespace MLAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.Write(HandleObjectSpawning);
|
writer.Write(HandleObjectSpawning);
|
||||||
writer.Write(CompressMessages);
|
writer.Write(EnableEncryption);
|
||||||
writer.Write(EncryptMessages);
|
|
||||||
writer.Write(AllowPassthroughMessages);
|
writer.Write(AllowPassthroughMessages);
|
||||||
writer.Write(EnableSceneSwitching);
|
writer.Write(EnableSceneSwitching);
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,9 @@
|
|||||||
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
|
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="IntXLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1744b76c74eaee1e, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\IntX.1.0.1.0\lib\net20\IntXLib.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
@ -62,6 +65,9 @@
|
|||||||
<Compile Include="Data\TrackedPointData.cs" />
|
<Compile Include="Data\TrackedPointData.cs" />
|
||||||
<Compile Include="MonoBehaviours\Prototyping\NetworkedAnimator.cs" />
|
<Compile Include="MonoBehaviours\Prototyping\NetworkedAnimator.cs" />
|
||||||
<Compile Include="MonoBehaviours\Prototyping\NetworkedNavMeshAgent.cs" />
|
<Compile Include="MonoBehaviours\Prototyping\NetworkedNavMeshAgent.cs" />
|
||||||
|
<Compile Include="NetworkingManagerComponents\CryptographyHelper.cs" />
|
||||||
|
<Compile Include="NetworkingManagerComponents\DiffieHellman.cs" />
|
||||||
|
<Compile Include="NetworkingManagerComponents\EllipticCurve.cs" />
|
||||||
<Compile Include="NetworkingManagerComponents\LagCompensationManager.cs" />
|
<Compile Include="NetworkingManagerComponents\LagCompensationManager.cs" />
|
||||||
<Compile Include="MonoBehaviours\Core\NetworkedBehaviour.cs" />
|
<Compile Include="MonoBehaviours\Core\NetworkedBehaviour.cs" />
|
||||||
<Compile Include="Data\NetworkedClient.cs" />
|
<Compile Include="Data\NetworkedClient.cs" />
|
||||||
@ -79,5 +85,8 @@
|
|||||||
<Compile Include="Data\ClientIdKey.cs" />
|
<Compile Include="Data\ClientIdKey.cs" />
|
||||||
<Compile Include="NetworkingManagerComponents\MessageChunker.cs" />
|
<Compile Include="NetworkingManagerComponents\MessageChunker.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
@ -7,6 +7,7 @@ using System.IO;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace MLAPI
|
namespace MLAPI
|
||||||
{
|
{
|
||||||
@ -51,6 +52,10 @@ namespace MLAPI
|
|||||||
|
|
||||||
public NetworkingConfiguration NetworkConfig;
|
public NetworkingConfiguration NetworkConfig;
|
||||||
|
|
||||||
|
private EllipticDiffieHellman clientDiffieHellman;
|
||||||
|
private Dictionary<int, byte[]> diffieHellmanPublicKeys;
|
||||||
|
private byte[] clientAesKey;
|
||||||
|
|
||||||
private void OnValidate()
|
private void OnValidate()
|
||||||
{
|
{
|
||||||
if (SpawnablePrefabs != null)
|
if (SpawnablePrefabs != null)
|
||||||
@ -88,6 +93,7 @@ namespace MLAPI
|
|||||||
pendingClients = new HashSet<int>();
|
pendingClients = new HashSet<int>();
|
||||||
connectedClients = new Dictionary<int, NetworkedClient>();
|
connectedClients = new Dictionary<int, NetworkedClient>();
|
||||||
messageBuffer = new byte[NetworkConfig.MessageBufferSize];
|
messageBuffer = new byte[NetworkConfig.MessageBufferSize];
|
||||||
|
diffieHellmanPublicKeys = new Dictionary<int, byte[]>();
|
||||||
MessageManager.channels = new Dictionary<string, int>();
|
MessageManager.channels = new Dictionary<string, int>();
|
||||||
MessageManager.messageTypes = new Dictionary<string, ushort>();
|
MessageManager.messageTypes = new Dictionary<string, ushort>();
|
||||||
MessageManager.messageCallbacks = new Dictionary<ushort, Dictionary<int, Action<int, byte[]>>>();
|
MessageManager.messageCallbacks = new Dictionary<ushort, Dictionary<int, Action<int, byte[]>>>();
|
||||||
@ -374,15 +380,29 @@ namespace MLAPI
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
byte[] diffiePublic = new byte[0];
|
||||||
|
if(NetworkConfig.EnableEncryption)
|
||||||
|
{
|
||||||
|
clientDiffieHellman = new EllipticDiffieHellman(EllipticDiffieHellman.DEFAULT_CURVE, EllipticDiffieHellman.DEFAULT_GENERATOR, EllipticDiffieHellman.DEFAULT_ORDER);
|
||||||
|
diffiePublic = clientDiffieHellman.GetPublicKey();
|
||||||
|
}
|
||||||
|
|
||||||
int sizeOfStream = 32;
|
int sizeOfStream = 32;
|
||||||
if (NetworkConfig.ConnectionApproval)
|
if (NetworkConfig.ConnectionApproval)
|
||||||
sizeOfStream += 2 + NetworkConfig.ConnectionData.Length;
|
sizeOfStream += 2 + NetworkConfig.ConnectionData.Length;
|
||||||
|
if (NetworkConfig.EnableEncryption)
|
||||||
|
sizeOfStream += 2 + diffiePublic.Length;
|
||||||
|
|
||||||
using (MemoryStream writeStream = new MemoryStream(sizeOfStream))
|
using (MemoryStream writeStream = new MemoryStream(sizeOfStream))
|
||||||
{
|
{
|
||||||
using (BinaryWriter writer = new BinaryWriter(writeStream))
|
using (BinaryWriter writer = new BinaryWriter(writeStream))
|
||||||
{
|
{
|
||||||
writer.Write(NetworkConfig.GetConfig());
|
writer.Write(NetworkConfig.GetConfig());
|
||||||
|
if (NetworkConfig.EnableEncryption)
|
||||||
|
{
|
||||||
|
writer.Write((ushort)diffiePublic.Length);
|
||||||
|
writer.Write(diffiePublic);
|
||||||
|
}
|
||||||
if (NetworkConfig.ConnectionApproval)
|
if (NetworkConfig.ConnectionApproval)
|
||||||
{
|
{
|
||||||
writer.Write((ushort)NetworkConfig.ConnectionData.Length);
|
writer.Write((ushort)NetworkConfig.ConnectionData.Length);
|
||||||
@ -471,6 +491,14 @@ namespace MLAPI
|
|||||||
|
|
||||||
ushort bytesToRead = reader.ReadUInt16();
|
ushort bytesToRead = reader.ReadUInt16();
|
||||||
byte[] incommingData = reader.ReadBytes(bytesToRead);
|
byte[] incommingData = reader.ReadBytes(bytesToRead);
|
||||||
|
if(NetworkConfig.EncryptedChannels.Contains(channelId))
|
||||||
|
{
|
||||||
|
//Encrypted message
|
||||||
|
if (isServer)
|
||||||
|
incommingData = CryptographyHelper.Decrypt(incommingData, connectedClients[clientId].AesKey);
|
||||||
|
else
|
||||||
|
incommingData = CryptographyHelper.Decrypt(incommingData, clientAesKey);
|
||||||
|
}
|
||||||
|
|
||||||
if (isServer && isPassthrough && !NetworkConfig.RegisteredPassthroughMessageTypes.Contains(messageType))
|
if (isServer && isPassthrough && !NetworkConfig.RegisteredPassthroughMessageTypes.Contains(messageType))
|
||||||
{
|
{
|
||||||
@ -555,6 +583,14 @@ namespace MLAPI
|
|||||||
DisconnectClient(clientId);
|
DisconnectClient(clientId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
byte[] aesKey = new byte[0];
|
||||||
|
if(NetworkConfig.EnableEncryption)
|
||||||
|
{
|
||||||
|
ushort diffiePublicSize = messageReader.ReadUInt16();
|
||||||
|
byte[] diffiePublic = messageReader.ReadBytes(diffiePublicSize);
|
||||||
|
diffieHellmanPublicKeys.Add(clientId, diffiePublic);
|
||||||
|
|
||||||
|
}
|
||||||
if (NetworkConfig.ConnectionApproval)
|
if (NetworkConfig.ConnectionApproval)
|
||||||
{
|
{
|
||||||
ushort bufferSize = messageReader.ReadUInt16();
|
ushort bufferSize = messageReader.ReadUInt16();
|
||||||
@ -583,6 +619,30 @@ namespace MLAPI
|
|||||||
sceneIndex = messageReader.ReadUInt32();
|
sceneIndex = messageReader.ReadUInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NetworkConfig.EnableEncryption)
|
||||||
|
{
|
||||||
|
ushort keyLength = messageReader.ReadUInt16();
|
||||||
|
byte[] serverPublicKey = messageReader.ReadBytes(keyLength);
|
||||||
|
clientAesKey = clientDiffieHellman.GetSharedSecret(serverPublicKey);
|
||||||
|
if (NetworkConfig.SignKeyExchange)
|
||||||
|
{
|
||||||
|
ushort signatureLength = messageReader.ReadUInt16();
|
||||||
|
byte[] publicKeySignature = messageReader.ReadBytes(signatureLength);
|
||||||
|
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.PersistKeyInCsp = false;
|
||||||
|
rsa.FromXmlString(NetworkConfig.RSAPublicKey);
|
||||||
|
if(!rsa.VerifyData(serverPublicKey, new SHA512CryptoServiceProvider(), publicKeySignature))
|
||||||
|
{
|
||||||
|
//Man in the middle.
|
||||||
|
Debug.LogWarning("MLAPI: Signature doesnt match for the key exchange public part. Disconnecting");
|
||||||
|
StopClient();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float netTime = messageReader.ReadSingle();
|
float netTime = messageReader.ReadSingle();
|
||||||
int remoteStamp = messageReader.ReadInt32();
|
int remoteStamp = messageReader.ReadInt32();
|
||||||
int msDelay = NetworkTransport.GetRemoteDelayTimeMS(hostId, clientId, remoteStamp, out error);
|
int msDelay = NetworkTransport.GetRemoteDelayTimeMS(hostId, clientId, remoteStamp, out error);
|
||||||
@ -901,8 +961,18 @@ namespace MLAPI
|
|||||||
writer.Write(orderId.Value);
|
writer.Write(orderId.Value);
|
||||||
writer.Write(true);
|
writer.Write(true);
|
||||||
writer.Write(sourceId);
|
writer.Write(sourceId);
|
||||||
writer.Write((ushort)data.Length);
|
if(NetworkConfig.EncryptedChannels.Contains(channelId))
|
||||||
writer.Write(data);
|
{
|
||||||
|
//Encrypted message
|
||||||
|
byte[] encrypted = CryptographyHelper.Encrypt(data, connectedClients[targetId].AesKey);
|
||||||
|
writer.Write((ushort)encrypted.Length);
|
||||||
|
writer.Write(encrypted);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.Write((ushort)data.Length);
|
||||||
|
writer.Write(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
NetworkTransport.QueueMessageForSending(hostId, targetId, channelId, stream.GetBuffer(), sizeOfStream, out error);
|
NetworkTransport.QueueMessageForSending(hostId, targetId, channelId, stream.GetBuffer(), sizeOfStream, out error);
|
||||||
}
|
}
|
||||||
@ -951,8 +1021,25 @@ namespace MLAPI
|
|||||||
writer.Write(isPassthrough);
|
writer.Write(isPassthrough);
|
||||||
if (isPassthrough)
|
if (isPassthrough)
|
||||||
writer.Write(clientId);
|
writer.Write(clientId);
|
||||||
writer.Write((ushort)data.Length);
|
|
||||||
writer.Write(data);
|
if (NetworkConfig.EncryptedChannels.Contains(MessageManager.channels[channelName]))
|
||||||
|
{
|
||||||
|
//This is an encrypted message.
|
||||||
|
byte[] encrypted;
|
||||||
|
if (isServer)
|
||||||
|
encrypted = CryptographyHelper.Encrypt(data, connectedClients[clientId].AesKey);
|
||||||
|
else
|
||||||
|
encrypted = CryptographyHelper.Encrypt(data, clientAesKey);
|
||||||
|
|
||||||
|
writer.Write((ushort)encrypted.Length);
|
||||||
|
writer.Write(encrypted);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Send in plaintext.
|
||||||
|
writer.Write((ushort)data.Length);
|
||||||
|
writer.Write(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isPassthrough)
|
if (isPassthrough)
|
||||||
clientId = serverClientId;
|
clientId = serverClientId;
|
||||||
@ -965,7 +1052,12 @@ namespace MLAPI
|
|||||||
|
|
||||||
internal void Send(int[] clientIds, string messageType, string channelName, byte[] data, uint? networkId = null, ushort? orderId = null)
|
internal void Send(int[] clientIds, string messageType, string channelName, byte[] data, uint? networkId = null, ushort? orderId = null)
|
||||||
{
|
{
|
||||||
int sizeOfStream = 6;
|
if (NetworkConfig.EncryptedChannels.Contains(MessageManager.channels[channelName]))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: Cannot send messages over encrypted channel to multiple clients.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int sizeOfStream = 6;
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
sizeOfStream += 4;
|
sizeOfStream += 4;
|
||||||
if (orderId != null)
|
if (orderId != null)
|
||||||
@ -1007,6 +1099,12 @@ namespace MLAPI
|
|||||||
|
|
||||||
internal void Send(List<int> clientIds, string messageType, string channelName, byte[] data, uint? networkId = null, ushort? orderId = null)
|
internal void Send(List<int> clientIds, string messageType, string channelName, byte[] data, uint? networkId = null, ushort? orderId = null)
|
||||||
{
|
{
|
||||||
|
if (NetworkConfig.EncryptedChannels.Contains(MessageManager.channels[channelName]))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: Cannot send messages over encrypted channel to multiple clients.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
|
//2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
|
||||||
int sizeOfStream = 6;
|
int sizeOfStream = 6;
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
@ -1050,6 +1148,12 @@ namespace MLAPI
|
|||||||
|
|
||||||
internal void Send(string messageType, string channelName, byte[] data, uint? networkId = null, ushort? orderId = null)
|
internal void Send(string messageType, string channelName, byte[] data, uint? networkId = null, ushort? orderId = null)
|
||||||
{
|
{
|
||||||
|
if (NetworkConfig.EncryptedChannels.Contains(MessageManager.channels[channelName]))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: Cannot send messages over encrypted channel to multiple clients.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
|
//2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
|
||||||
int sizeOfStream = 6;
|
int sizeOfStream = 6;
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
@ -1094,6 +1198,12 @@ namespace MLAPI
|
|||||||
|
|
||||||
internal void Send(string messageType, string channelName, byte[] data, int clientIdToIgnore, uint? networkId = null, ushort? orderId = null)
|
internal void Send(string messageType, string channelName, byte[] data, int clientIdToIgnore, uint? networkId = null, ushort? orderId = null)
|
||||||
{
|
{
|
||||||
|
if (NetworkConfig.EncryptedChannels.Contains(MessageManager.channels[channelName]))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: Cannot send messages over encrypted channel to multiple clients.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
|
//2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
|
||||||
int sizeOfStream = 5;
|
int sizeOfStream = 5;
|
||||||
if (networkId != null)
|
if (networkId != null)
|
||||||
@ -1142,10 +1252,16 @@ namespace MLAPI
|
|||||||
{
|
{
|
||||||
if (!isServer)
|
if (!isServer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pendingClients.Contains(clientId))
|
if (pendingClients.Contains(clientId))
|
||||||
pendingClients.Remove(clientId);
|
pendingClients.Remove(clientId);
|
||||||
|
|
||||||
if (connectedClients.ContainsKey(clientId))
|
if (connectedClients.ContainsKey(clientId))
|
||||||
connectedClients.Remove(clientId);
|
connectedClients.Remove(clientId);
|
||||||
|
|
||||||
|
if (diffieHellmanPublicKeys.ContainsKey(clientId))
|
||||||
|
diffieHellmanPublicKeys.Remove(clientId);
|
||||||
|
|
||||||
NetworkTransport.Disconnect(hostId, clientId, out error);
|
NetworkTransport.Disconnect(hostId, clientId, out error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1188,9 +1304,34 @@ namespace MLAPI
|
|||||||
//Inform new client it got approved
|
//Inform new client it got approved
|
||||||
if (pendingClients.Contains(clientId))
|
if (pendingClients.Contains(clientId))
|
||||||
pendingClients.Remove(clientId);
|
pendingClients.Remove(clientId);
|
||||||
|
|
||||||
|
byte[] aesKey = new byte[0];
|
||||||
|
byte[] publicKey = new byte[0];
|
||||||
|
byte[] publicKeySignature = new byte[0];
|
||||||
|
if (NetworkConfig.EnableEncryption)
|
||||||
|
{
|
||||||
|
EllipticDiffieHellman diffieHellman = new EllipticDiffieHellman(EllipticDiffieHellman.DEFAULT_CURVE, EllipticDiffieHellman.DEFAULT_GENERATOR, EllipticDiffieHellman.DEFAULT_ORDER);
|
||||||
|
aesKey = diffieHellman.GetSharedSecret(diffieHellmanPublicKeys[clientId]);
|
||||||
|
publicKey = diffieHellman.GetPublicKey();
|
||||||
|
|
||||||
|
if (diffieHellmanPublicKeys.ContainsKey(clientId))
|
||||||
|
diffieHellmanPublicKeys.Remove(clientId);
|
||||||
|
|
||||||
|
if (NetworkConfig.SignKeyExchange)
|
||||||
|
{
|
||||||
|
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.PersistKeyInCsp = false;
|
||||||
|
rsa.FromXmlString(NetworkConfig.RSAPrivateKey);
|
||||||
|
publicKeySignature = rsa.SignData(publicKeySignature, new SHA512CryptoServiceProvider());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NetworkedClient client = new NetworkedClient()
|
NetworkedClient client = new NetworkedClient()
|
||||||
{
|
{
|
||||||
ClientId = clientId
|
ClientId = clientId,
|
||||||
|
AesKey = aesKey
|
||||||
};
|
};
|
||||||
connectedClients.Add(clientId, client);
|
connectedClients.Add(clientId, client);
|
||||||
|
|
||||||
@ -1200,18 +1341,26 @@ namespace MLAPI
|
|||||||
GameObject go = SpawnManager.SpawnPlayerObject(clientId, networkId);
|
GameObject go = SpawnManager.SpawnPlayerObject(clientId, networkId);
|
||||||
connectedClients[clientId].PlayerObject = go;
|
connectedClients[clientId].PlayerObject = go;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int sizeOfStream = 16 + ((connectedClients.Count - 1) * 4);
|
int sizeOfStream = 16 + ((connectedClients.Count - 1) * 4);
|
||||||
|
|
||||||
int amountOfObjectsToSend = SpawnManager.spawnedObjects.Values.Count(x => x.ServerOnly == false);
|
int amountOfObjectsToSend = SpawnManager.spawnedObjects.Values.Count(x => x.ServerOnly == false);
|
||||||
|
|
||||||
if(NetworkConfig.HandleObjectSpawning)
|
if (NetworkConfig.HandleObjectSpawning)
|
||||||
{
|
{
|
||||||
sizeOfStream += 4;
|
sizeOfStream += 4;
|
||||||
sizeOfStream += 14 * amountOfObjectsToSend;
|
sizeOfStream += 14 * amountOfObjectsToSend;
|
||||||
}
|
}
|
||||||
if(NetworkConfig.EnableSceneSwitching)
|
|
||||||
|
if (NetworkConfig.EnableEncryption)
|
||||||
|
{
|
||||||
|
sizeOfStream += 2 + publicKey.Length;
|
||||||
|
if (NetworkConfig.SignKeyExchange)
|
||||||
|
{
|
||||||
|
sizeOfStream += 2 + publicKeySignature.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NetworkConfig.EnableSceneSwitching)
|
||||||
{
|
{
|
||||||
sizeOfStream += 4;
|
sizeOfStream += 4;
|
||||||
}
|
}
|
||||||
@ -1225,8 +1374,21 @@ namespace MLAPI
|
|||||||
{
|
{
|
||||||
writer.Write(NetworkSceneManager.CurrentSceneIndex);
|
writer.Write(NetworkSceneManager.CurrentSceneIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NetworkConfig.EnableEncryption)
|
||||||
|
{
|
||||||
|
writer.Write((ushort)publicKey.Length);
|
||||||
|
writer.Write(publicKey);
|
||||||
|
if (NetworkConfig.SignKeyExchange)
|
||||||
|
{
|
||||||
|
writer.Write((ushort)publicKeySignature.Length);
|
||||||
|
writer.Write(publicKeySignature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
writer.Write(NetworkTime);
|
writer.Write(NetworkTime);
|
||||||
writer.Write(NetworkTransport.GetNetworkTimestamp());
|
writer.Write(NetworkTransport.GetNetworkTimestamp());
|
||||||
|
|
||||||
writer.Write(connectedClients.Count - 1);
|
writer.Write(connectedClients.Count - 1);
|
||||||
foreach (KeyValuePair<int, NetworkedClient> item in connectedClients)
|
foreach (KeyValuePair<int, NetworkedClient> item in connectedClients)
|
||||||
{
|
{
|
||||||
@ -1292,6 +1454,10 @@ namespace MLAPI
|
|||||||
{
|
{
|
||||||
if (pendingClients.Contains(clientId))
|
if (pendingClients.Contains(clientId))
|
||||||
pendingClients.Remove(clientId);
|
pendingClients.Remove(clientId);
|
||||||
|
|
||||||
|
if (diffieHellmanPublicKeys.ContainsKey(clientId))
|
||||||
|
diffieHellmanPublicKeys.Remove(clientId);
|
||||||
|
|
||||||
NetworkTransport.Disconnect(hostId, clientId, out error);
|
NetworkTransport.Disconnect(hostId, clientId, out error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
MLAPI/NetworkingManagerComponents/CryptographyHelper.cs
Normal file
50
MLAPI/NetworkingManagerComponents/CryptographyHelper.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MLAPI.NetworkingManagerComponents
|
||||||
|
{
|
||||||
|
public static class CryptographyHelper
|
||||||
|
{
|
||||||
|
public static byte[] Decrypt(byte[] encryptedBuffer, byte[] key)
|
||||||
|
{
|
||||||
|
byte[] iv = new byte[16];
|
||||||
|
Array.Copy(encryptedBuffer, 0, iv, 0, 16);
|
||||||
|
|
||||||
|
using (MemoryStream stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (RijndaelManaged aes = new RijndaelManaged())
|
||||||
|
{
|
||||||
|
aes.IV = iv;
|
||||||
|
aes.Key = key;
|
||||||
|
using (CryptoStream cs = new CryptoStream(stream, aes.CreateDecryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(encryptedBuffer, 16, encryptedBuffer.Length - 16);
|
||||||
|
}
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] Encrypt(byte[] clearBuffer, byte[] key)
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (RijndaelManaged aes = new RijndaelManaged())
|
||||||
|
{
|
||||||
|
aes.Key = key;
|
||||||
|
aes.GenerateIV();
|
||||||
|
using (CryptoStream cs = new CryptoStream(stream, aes.CreateEncryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(clearBuffer, 0, clearBuffer.Length);
|
||||||
|
}
|
||||||
|
byte[] encrypted = stream.ToArray();
|
||||||
|
byte[] final = new byte[encrypted.Length + 16];
|
||||||
|
Array.Copy(aes.IV, final, 16);
|
||||||
|
Array.Copy(encrypted, 0, final, 16, encrypted.Length);
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
MLAPI/NetworkingManagerComponents/DiffieHellman.cs
Normal file
104
MLAPI/NetworkingManagerComponents/DiffieHellman.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using IntXLib;
|
||||||
|
using System.Text;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace MLAPI.NetworkingManagerComponents
|
||||||
|
{
|
||||||
|
public class EllipticDiffieHellman
|
||||||
|
{
|
||||||
|
protected static readonly RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider();
|
||||||
|
public static readonly IntX DEFAULT_PRIME = (new IntX(1) << 255) - 19;
|
||||||
|
public static readonly IntX DEFAULT_ORDER = (new IntX(1) << 252) + IntX.Parse("27742317777372353535851937790883648493");
|
||||||
|
public static readonly EllipticCurve DEFAULT_CURVE = new EllipticCurve(486662, 1, DEFAULT_PRIME, EllipticCurve.CurveType.Montgomery);
|
||||||
|
public static readonly CurvePoint DEFAULT_GENERATOR = new CurvePoint(9, IntX.Parse("14781619447589544791020593568409986887264606134616475288964881837755586237401"));
|
||||||
|
|
||||||
|
protected readonly EllipticCurve curve;
|
||||||
|
public readonly IntX priv;
|
||||||
|
protected readonly CurvePoint generator, pub;
|
||||||
|
|
||||||
|
|
||||||
|
public EllipticDiffieHellman(EllipticCurve curve, CurvePoint generator, IntX order, byte[] priv = null)
|
||||||
|
{
|
||||||
|
this.curve = curve;
|
||||||
|
this.generator = generator;
|
||||||
|
|
||||||
|
// Generate private key
|
||||||
|
if (priv == null)
|
||||||
|
{
|
||||||
|
byte[] max = order.ToArray();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
byte[] p1 = new byte[5 /*rand.Next(max.Length) + 1*/];
|
||||||
|
|
||||||
|
rand.GetBytes(p1);
|
||||||
|
|
||||||
|
if (p1.Length == max.Length) p1[p1.Length - 1] %= max[max.Length - 1];
|
||||||
|
else p1[p1.Length - 1] &= 127;
|
||||||
|
|
||||||
|
this.priv = DHHelper.FromArray(p1);
|
||||||
|
} while (this.priv<2);
|
||||||
|
}
|
||||||
|
else this.priv = DHHelper.FromArray(priv);
|
||||||
|
|
||||||
|
// Generate public key
|
||||||
|
pub = curve.Multiply(generator, this.priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetPublicKey()
|
||||||
|
{
|
||||||
|
byte[] p1 = pub.X.ToArray();
|
||||||
|
byte[] p2 = pub.Y.ToArray();
|
||||||
|
|
||||||
|
byte[] ser = new byte[4 + p1.Length + p2.Length];
|
||||||
|
ser[0] = (byte)(p1.Length & 255);
|
||||||
|
ser[1] = (byte)((p1.Length >> 8) & 255);
|
||||||
|
ser[2] = (byte)((p1.Length >> 16) & 255);
|
||||||
|
ser[3] = (byte)((p1.Length >> 24) & 255);
|
||||||
|
Array.Copy(p1, 0, ser, 4, p1.Length);
|
||||||
|
Array.Copy(p2, 0, ser, 4 + p1.Length, p2.Length);
|
||||||
|
|
||||||
|
return ser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetPrivateKey() => priv.ToArray();
|
||||||
|
|
||||||
|
public byte[] GetSharedSecret(byte[] pK)
|
||||||
|
{
|
||||||
|
byte[] p1 = new byte[pK[0] | (pK[1]<<8) | (pK[2]<<16) | (pK[3]<<24)]; // Reconstruct x-axis size
|
||||||
|
byte[] p2 = new byte[pK.Length - p1.Length - 4];
|
||||||
|
Array.Copy(pK, 4, p1, 0, p1.Length);
|
||||||
|
Array.Copy(pK, 4 + p1.Length, p2, 0, p2.Length);
|
||||||
|
|
||||||
|
CurvePoint remotePublic = new CurvePoint(DHHelper.FromArray(p1), DHHelper.FromArray(p2));
|
||||||
|
|
||||||
|
byte[] secret = curve.Multiply(remotePublic, priv).X.ToArray(); // Use the x-coordinate as the shared secret
|
||||||
|
|
||||||
|
// PBKDF2-HMAC-SHA1 (Common shared secret generation method)
|
||||||
|
return new Rfc2898DeriveBytes(secret, Encoding.UTF8.GetBytes("P1sN0R4inb0wPl5P1sPls"), 1000).GetBytes(32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DHHelper
|
||||||
|
{
|
||||||
|
public static byte[] ToArray(this IntX v)
|
||||||
|
{
|
||||||
|
v.GetInternalState(out uint[] digits, out bool negative);
|
||||||
|
byte[] b = DigitConverter.ToBytes(digits);
|
||||||
|
byte[] b1 = new byte[b.Length + 1];
|
||||||
|
Array.Copy(b, b1, b.Length);
|
||||||
|
b1[b.Length] = (byte)(negative ? 1 : 0);
|
||||||
|
return b1;
|
||||||
|
}
|
||||||
|
public static IntX FromArray(byte[] b)
|
||||||
|
{
|
||||||
|
if (b.Length == 0) return new IntX();
|
||||||
|
byte[] b1 = new byte[b.Length - 1];
|
||||||
|
Array.Copy(b, b1, b1.Length);
|
||||||
|
uint[] u = DigitConverter.FromBytes(b1);
|
||||||
|
return new IntX(u, b[b.Length - 1]==1);
|
||||||
|
}
|
||||||
|
public static bool BitAt(this uint[] data, long index) => (data[index / 32] & (1 << (int)(index % 32))) != 0;
|
||||||
|
public static IntX Abs(this IntX i) => i < 0 ? -i : i;
|
||||||
|
}
|
||||||
|
}
|
189
MLAPI/NetworkingManagerComponents/EllipticCurve.cs
Normal file
189
MLAPI/NetworkingManagerComponents/EllipticCurve.cs
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using IntXLib;
|
||||||
|
|
||||||
|
namespace MLAPI.NetworkingManagerComponents
|
||||||
|
{
|
||||||
|
public class CurvePoint
|
||||||
|
{
|
||||||
|
public static readonly CurvePoint POINT_AT_INFINITY = new CurvePoint();
|
||||||
|
public IntX X { get; private set; }
|
||||||
|
public IntX Y { get; private set; }
|
||||||
|
private bool pai = false;
|
||||||
|
public CurvePoint(IntX x, IntX y)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
private CurvePoint() { pai = true; } // Accessing corrdinates causes undocumented behaviour
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return pai ? "(POINT_AT_INFINITY)" : "(" + X + ", " + Y + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EllipticCurve
|
||||||
|
{
|
||||||
|
public enum CurveType { Weierstrass, Montgomery }
|
||||||
|
|
||||||
|
protected readonly IntX a, b, modulo;
|
||||||
|
protected readonly CurveType type;
|
||||||
|
|
||||||
|
public EllipticCurve(IntX a, IntX b, IntX modulo, CurveType type = CurveType.Weierstrass)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
(type==CurveType.Weierstrass && (4 * a * a * a) + (27 * b * b) == 0) || // Unfavourable Weierstrass curves
|
||||||
|
(type==CurveType.Montgomery && b * (a * a - 4)==0) // Unfavourable Montgomery curves
|
||||||
|
) throw new Exception("Unfavourable curve");
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
this.modulo = modulo;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CurvePoint Add(CurvePoint p1, CurvePoint p2)
|
||||||
|
{
|
||||||
|
#if SAFE_MATH
|
||||||
|
CheckOnCurve(p1);
|
||||||
|
CheckOnCurve(p2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Special cases
|
||||||
|
if (p1 == CurvePoint.POINT_AT_INFINITY && p2 == CurvePoint.POINT_AT_INFINITY) return CurvePoint.POINT_AT_INFINITY;
|
||||||
|
else if (p1 == CurvePoint.POINT_AT_INFINITY) return p2;
|
||||||
|
else if (p2 == CurvePoint.POINT_AT_INFINITY) return p1;
|
||||||
|
else if (p1.X == p2.X && p1.Y == Inverse(p2).Y) return CurvePoint.POINT_AT_INFINITY;
|
||||||
|
|
||||||
|
IntX x3 = 0, y3 = 0;
|
||||||
|
if (type == CurveType.Weierstrass)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
x3 = Mod((slope * slope) - p1.X - p2.X);
|
||||||
|
y3 = Mod(-((slope * x3) + p1.Y - (slope * p1.X)));
|
||||||
|
}
|
||||||
|
else if (type == CurveType.Montgomery)
|
||||||
|
{
|
||||||
|
if ((p1.X == p2.X && p1.Y == p2.Y))
|
||||||
|
{
|
||||||
|
IntX q = 3 * p1.X;
|
||||||
|
IntX w = q * p1.X;
|
||||||
|
|
||||||
|
IntX e = 2 * a;
|
||||||
|
IntX r = e * p1.X;
|
||||||
|
|
||||||
|
IntX t = 2 * b;
|
||||||
|
IntX y = t * p1.Y;
|
||||||
|
|
||||||
|
IntX u = MulInverse(y);
|
||||||
|
|
||||||
|
IntX o = w + e + 1;
|
||||||
|
IntX p = o * u;
|
||||||
|
}
|
||||||
|
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
|
||||||
|
x3 = Mod(b * co * co - a - p1.X - p2.X);
|
||||||
|
y3 = Mod(((2 * p1.X + p2.X + a) * co) - (b * co * co * co) - p1.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CurvePoint(x3, y3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CurvePoint Multiply(CurvePoint p, IntX scalar)
|
||||||
|
{
|
||||||
|
if (scalar <= 0) throw new Exception("Cannot multiply by a scalar which is <= 0");
|
||||||
|
if (p == CurvePoint.POINT_AT_INFINITY) return CurvePoint.POINT_AT_INFINITY;
|
||||||
|
|
||||||
|
CurvePoint p1 = new CurvePoint(p.X, p.Y);
|
||||||
|
scalar.GetInternalState(out uint[] u, out bool b);
|
||||||
|
long high_bit = -1;
|
||||||
|
for (int i = u.Length - 1; i>=0; --i)
|
||||||
|
if (u[i] != 0)
|
||||||
|
{
|
||||||
|
for(int j = 31; j>=0; --j)
|
||||||
|
if ((u[i] & (1<<j))!=0)
|
||||||
|
{
|
||||||
|
high_bit = j + i * 32;
|
||||||
|
goto Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Next:
|
||||||
|
|
||||||
|
// Double-and-add method
|
||||||
|
while(high_bit >= 0)
|
||||||
|
{
|
||||||
|
p1 = Add(p1, p1); // Double
|
||||||
|
if ((u.BitAt(high_bit)))
|
||||||
|
p1 = Add(p1, p); // Add
|
||||||
|
--high_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IntX MulInverse(IntX eq) => MulInverse(eq, modulo);
|
||||||
|
public static IntX MulInverse(IntX eq, IntX modulo)
|
||||||
|
{
|
||||||
|
eq = Mod(eq, modulo);
|
||||||
|
Stack<IntX> collect = new Stack<IntX>();
|
||||||
|
IntX v = modulo; // Copy modulo
|
||||||
|
IntX m;
|
||||||
|
while((m = v % eq) != 0)
|
||||||
|
{
|
||||||
|
collect.Push(-v/eq/*-(m.l_div)*/);
|
||||||
|
v = eq;
|
||||||
|
eq = m;
|
||||||
|
}
|
||||||
|
if (collect.Count == 0) return 1;
|
||||||
|
v = 1;
|
||||||
|
m = collect.Pop();
|
||||||
|
while (collect.Count > 0)
|
||||||
|
{
|
||||||
|
eq = m;
|
||||||
|
m = v + (m * collect.Pop());
|
||||||
|
v = eq;
|
||||||
|
}
|
||||||
|
return Mod(m, modulo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CurvePoint Inverse(CurvePoint p) => Inverse(p, modulo);
|
||||||
|
protected static CurvePoint Inverse(CurvePoint p, IntX modulo) => new CurvePoint(p.X, Mod(-p.Y, modulo));
|
||||||
|
|
||||||
|
public bool IsOnCurve(CurvePoint p)
|
||||||
|
{
|
||||||
|
try { CheckOnCurve(p); }
|
||||||
|
catch { return false; }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
protected void CheckOnCurve(CurvePoint p)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
p!=CurvePoint.POINT_AT_INFINITY && // The point at infinity is asserted to be on the curve
|
||||||
|
(type == CurveType.Weierstrass && Mod(p.Y * p.Y) != Mod((p.X * p.X * p.X) + (p.X * a) + b)) || // Weierstrass formula
|
||||||
|
(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
|
||||||
|
) throw new Exception("Point is not on curve");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IntX Mod(IntX b) => Mod(b, modulo);
|
||||||
|
|
||||||
|
private static IntX Mod(IntX x, IntX m)
|
||||||
|
{
|
||||||
|
IntX r = x.Abs() > m ? x % m : x;
|
||||||
|
return r < 0 ? r + m : r;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static IntX ModPow(IntX x, IntX power, IntX prime)
|
||||||
|
{
|
||||||
|
IntX result = 1;
|
||||||
|
bool setBit = false;
|
||||||
|
while(power > 0)
|
||||||
|
{
|
||||||
|
x %= prime;
|
||||||
|
setBit = (power & 1) == 1;
|
||||||
|
power >>= 1;
|
||||||
|
if (setBit) result *= x;
|
||||||
|
x *= x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
MLAPI/packages.config
Normal file
4
MLAPI/packages.config
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="IntX" version="1.0.1.0" targetFramework="net35" />
|
||||||
|
</packages>
|
Loading…
x
Reference in New Issue
Block a user