Need help troubleshooting a logical error on Asynchronous Server Socket

advertisements

This program is about establishing connection between one server and multi client. The process of handshaking is the client generate a hash and send to the server.The server then will generate a pair of public and private key and encrypt the hash and send back the encrypt hash with the public key to the client.

My problem is the server did not respond the data what i want, the server will just respond the signature(encrypted hash) for public key instead.

my reputation not high enough to post the picture of the result so i will just type it out

  • Socket connected to {0}127.0.01:1100
  • sent {0} bytes to server : 8
  • signature: ??.p1?z??7/)??#u?m?????b?=???,?w???u?N?&f?
  • sent {0} bytes to server : 2
  • publickey: ??.p1?z??7/)??#u?m?????b?=???,?w???u?N?&f?

another problem is i don't know how to fix the server hanging program, there is a infinite while loop at server Asynchronous class at StartListening() method

There is 2 different project one for server and one for client

The server side code

the Asynchronous server socket code

using UnityEngine;
using System.Collections;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Security.Cryptography;
// State object for receiving data from remote device.
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder ();
}
public class AsynchronousServerSocket : MonoBehaviour
{
// Thread signal.
public static ManualResetEvent allDone =
new ManualResetEvent (false);
public AsynchronousServerSocket ()
{
}
public Socket listener;
public Server ServerClass;
public ASCIIEncoding myAscii =
new ASCIIEncoding ();
public void StartListening ()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry ("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList [0];
IPEndPoint localEndPoint = new IPEndPoint (ipAddress, 11000);
// Create a TCP/IP socket.
listener = new Socket
(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try {
listener.Bind (localEndPoint);
listener.Listen (1024);
while (true) {
// Set the event to nonsignaled state.
allDone.Reset ();
// Start an asynchronous socket to listen for connections.
Debug.Log ("Waiting for a connection...");
listener.BeginAccept
(new AsyncCallback (AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne ();
}
//StartCoroutine("StupidUnityHang");
} catch (Exception e) {
Debug.Log (e.ToString ());
}
}
public IEnumerator StupidUnityHang ()
{
do {
// Set the event to nonsignaled state.
allDone.Reset ();
// Start an asynchronous socket to listen for connections.
Debug.Log ("Waiting for a connection...");
listener.BeginAccept
(new AsyncCallback (AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne ();
yield return new WaitForSeconds (1);
} while(true);
}
public void AcceptCallback (IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set ();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept (ar);
// Create the state object.
StateObject state = new StateObject ();
state.workSocket = handler;
handler.BeginReceive (state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback (StageOne), state);
allDone.WaitOne ();
handler.BeginReceive (state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback (StageTwo), state);
//allDone.Set();
}
// sending client the signature and the public key
public void StageOne (IAsyncResult ar)
{
String content = String.Empty;
String check = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive (ar);
if (bytesRead > 0) {
state.sb.Append (Encoding.ASCII.GetString (state.buffer, 0, bytesRead));
content = state.sb.ToString ();
byte[] hashByte = myAscii.GetBytes (content);
ServerClass.GeneratePublicPrivateKey ();
byte [] signature = ServerClass.SendEncryptHash (hashByte);
content = myAscii.GetString (signature);
Send (handler, content);
}
}
public void StageTwo (IAsyncResult ar)
{
String content = String.Empty;
String check = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive (ar);
if (bytesRead > 0) {
//state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));
//content = state.sb.ToString();
//if(content =="PK")
//{
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider ();
RSAParameters publicKey = ServerClass.SendPublicKey ();
rsaCSP.ImportParameters (publicKey);
content = rsaCSP.ToXmlString (false);
Send (handler, content);
//}
}
}
private void Send (Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes (data);
// Begin sending the data to the remote device.
handler.BeginSend (byteData, 0, byteData.Length, 0,
new AsyncCallback (SendCallback), handler);
}
private void SendCallback (IAsyncResult ar)
{
try {
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend (ar);
Debug.Log ("Sent {0} bytes to client." + bytesSent);
handler.Shutdown (SocketShutdown.Both);
handler.Close ();
} catch (Exception e) {
Debug.Log (e.ToString ());
}
}
}

the server process code

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.IO;
using System.Text;
using System;
public class Server : MonoBehaviour
{
public RSAParameters rsaPrivateKey;
public RSAParameters rsaPublicKey;
public void GeneratePublicPrivateKey ()
{
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider ();
rsaPrivateKey = rsaCSP.ExportParameters (true);
rsaPublicKey = rsaCSP.ExportParameters (false);
}
public RSAParameters SendPublicKey ()
{
return rsaPublicKey;
}
public byte[] HashAndSign (byte[] encrypted)
{
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider ();
SHA1Managed hash = new SHA1Managed ();
byte[] hashedData;
rsaCSP.ImportParameters (rsaPrivateKey);
hashedData = hash.ComputeHash (encrypted);
return rsaCSP.SignHash (hashedData, CryptoConfig.MapNameToOID ("SHA1"));
}
public byte[] SendEncryptHash (byte[] tmp)
{
return HashAndSign (tmp);
}
public byte[] SendEncryptAESHash (byte[]hash, byte[]key, byte[]IV)
{
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider ();
rsaCSP.ImportParameters (rsaPrivateKey);
byte[] decryptedSessionKey = rsaCSP.Decrypt (key, false);
byte[] decryptedSessionIV = rsaCSP.Decrypt (IV, false);
return encrypt_function (hash, decryptedSessionKey, decryptedSessionIV);
}
private static byte[] encrypt_function (byte[] PlainBytes, byte[] Key, byte[] IV)
{
RijndaelManaged Crypto = null;
MemoryStream MemStream = null;
ICryptoTransform Encryptor = null;
CryptoStream Crypto_Stream = null;
try {
Crypto = new RijndaelManaged ();
Crypto.Key = Key;
Crypto.IV = IV;
MemStream = new MemoryStream ();
Encryptor = Crypto.CreateEncryptor (Crypto.Key, Crypto.IV);
Crypto_Stream = new CryptoStream (MemStream, Encryptor, CryptoStreamMode.Write);
Crypto_Stream.Write (PlainBytes, 0, PlainBytes.Length);
} finally {
if (Crypto != null)
Crypto.Clear ();
Crypto_Stream.Close ();
}
return MemStream.ToArray ();
}
}

Server Main Program

using UnityEngine;
using System.Collections;

public class ServerProgram : MonoBehaviour
{

public AsynchronousServerSocket AsynchronousServerClass;

public void Start ()
{
AsynchronousServerClass.StartListening ();
}
}

Client Side Code

Asynchronous Client Class

using UnityEngine;
using System.Collections;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Security.Cryptography;

// State object for receiving data from remote device.
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder ();
}

public class AsynchronousClientSocket : MonoBehaviour
{
// The port number for the remote device.
private const int port = 11000;

// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone = new ManualResetEvent (false);
private static ManualResetEvent sendDone = new ManualResetEvent (false);
private static ManualResetEvent receiveDone = new ManualResetEvent (false);

// The response from the remote device.
private String response = String.Empty;
public Client ClientClass;
public ASCIIEncoding myAscii = new ASCIIEncoding ();

public  void StartClient ()
{
// Connect to a remote device.
try {
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry ("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList [0];
IPEndPoint remoteEP = new IPEndPoint (ipAddress, port);

// Create a TCP/IP socket.
Socket client = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

// Connect to the remote endpoint.
client.BeginConnect (remoteEP, new AsyncCallback (ConnectCallback), client);
connectDone.WaitOne ();

byte[] hashByte = ClientClass.SendHash ();
string hashString = myAscii.GetString (hashByte);

// Send test data to the remote device.
Send (client, hashString);
sendDone.WaitOne ();

// Receive the response from the remote device.
Receive (client);
receiveDone.WaitOne ();
// Write the response to the console.
Debug.Log ("Signature: " + response);
byte[] signature = myAscii.GetBytes (response);

Send (client, "PK");
sendDone.WaitOne ();

Receive (client);
receiveDone.WaitOne ();
Debug.Log ("PublicKey: " + response);
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider ();
rsaCSP.FromXmlString (response);
RSAParameters publicKey = rsaCSP.ExportParameters (false);

if (ClientClass.VerifyHash (publicKey, hashByte, signature)) {
Debug.Log ("success");
} else {
Debug.Log ("problem");
}

// Release the socket.
client.Shutdown (SocketShutdown.Both);
client.Close ();

} catch (Exception e) {
Console.WriteLine (e.ToString ());
}
}

private void ConnectCallback (IAsyncResult ar)
{
try {
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;

// Complete the connection.
client.EndConnect (ar);

Debug.Log ("Socket connected to {0}" + client.RemoteEndPoint.ToString ());

// Signal that the connection has been made.
connectDone.Set ();
} catch (Exception e) {
Debug.Log (e.ToString ());
}
}

private void Receive (Socket client)
{
try {
// Create the state object.
StateObject state = new StateObject ();
state.workSocket = client;

// Begin receiving the data from the remote device.
client.BeginReceive (state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback (ReceiveCallback), state);
} catch (Exception e) {
Debug.Log (e.ToString ());
}
}

private void ReceiveCallback (IAsyncResult ar)
{
try {
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;

// Read data from the remote device.
int bytesRead = client.EndReceive (ar);

if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append (Encoding.ASCII.GetString (state.buffer, 0, bytesRead));

// Get the rest of the data.
client.BeginReceive (state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback (ReceiveCallback), state);
} else {
// All the data has arrived; put it in response.
if (state.sb.Length > 1) {
response = state.sb.ToString ();
}
// Signal that all bytes have been received.
receiveDone.Set ();
}
} catch (Exception e) {
Debug.Log (e.ToString ());
}
}

private void Send (Socket client, String data)
{
// Convert the string data to byte data using ASCII encoding.

byte[] byteData = Encoding.ASCII.GetBytes (data);

// Begin sending the data to the remote device.
client.BeginSend (byteData, 0, byteData.Length, 0, new AsyncCallback (SendCallback), client);
}

private void SendCallback (IAsyncResult ar)
{
try {
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;

// Complete sending the data to the remote device.
int bytesSent = client.EndSend (ar);
Debug.Log ("Sent {0} bytes to server." + bytesSent);

// Signal that all bytes have been sent.
sendDone.Set ();
} catch (Exception e) {
Debug.Log (e.ToString ());
}
}
}

Client processing class method

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.IO;
using System.Text;
using System;

public class Client : MonoBehaviour
{
public string hash;
public byte[] sessionKeyByte;
public byte[] sessionIVByte;
public byte[] sessionKey;
public byte[] sessionIV;
static readonly char[] AvailableCharacters = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '`', '~', '-',
'@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '=', '+', '/',
'{', '}', '[', ']', '|','\\', ':', ';', '"','\'', '<', '>', ',',
'.', '?', '!'
};

internal static string GenerateIdentifier (int length)
{
char[] identifier = new char[length];
byte[] randomData = new byte[length];

RNGCryptoServiceProvider rng =
new RNGCryptoServiceProvider ();
rng.GetBytes (randomData);

for (int idx = 0; idx < identifier.Length; idx++) {
int pos =
randomData [idx] % AvailableCharacters.Length;
identifier [idx] = AvailableCharacters [pos];
}
return new string (identifier);
}

public byte[] SendHash ()
{
hash = GenerateIdentifier (8);
ASCIIEncoding myAscii = new ASCIIEncoding ();
return myAscii.GetBytes (hash);
}

public bool VerifyHash
(RSAParameters rsaParams, byte[] signedData, byte[] signature)
{
RSACryptoServiceProvider rsaCSP =
new RSACryptoServiceProvider ();
SHA1Managed hash = new SHA1Managed ();
byte[] hashedData;

rsaCSP.ImportParameters (rsaParams);

hashedData = hash.ComputeHash (signedData);
return rsaCSP.VerifyHash
(hashedData, CryptoConfig.MapNameToOID ("SHA1"), signature);
}

public void EncryptSessionKey (RSAParameters temp)
{
RijndaelManaged Crypto = new RijndaelManaged ();
RSACryptoServiceProvider rsaCSP =
new RSACryptoServiceProvider ();
rsaCSP.ImportParameters (temp);

sessionKey = Crypto.Key;
sessionIV = Crypto.IV;
sessionKeyByte = rsaCSP.Encrypt (sessionKey, false);
sessionIVByte = rsaCSP.Encrypt (sessionIV, false);
}

public byte[] SendSessionKey ()
{
return sessionKeyByte;
}

public byte[] SendSessionIV ()
{
return sessionIVByte;
}

private static string decrypt_function (
byte[] Cipher_Text, byte[] Key, byte[] IV)
{
RijndaelManaged Crypto = null;
MemoryStream MemStream = null;
ICryptoTransform Decryptor = null;
CryptoStream Crypto_Stream = null;
StreamReader Stream_Read = null;
string Plain_Text;

try {
Crypto = new RijndaelManaged ();
Crypto.Key = Key;
Crypto.IV = IV;
MemStream = new MemoryStream
(Cipher_Text);
Decryptor = Crypto.CreateDecryptor
(Crypto.Key, Crypto.IV);
Crypto_Stream = new CryptoStream
(MemStream, Decryptor, CryptoStreamMode.Read);
Stream_Read = new StreamReader
(Crypto_Stream);
Plain_Text = Stream_Read.ReadToEnd ();

} finally {
if (Crypto != null)
Crypto.Clear ();

MemStream.Flush ();
MemStream.Close ();

}
return Plain_Text;
}

public string DecryptHash (byte[] temp)
{
return decrypt_function (temp, sessionKey, sessionIV);
}

public bool VerifySessionKey (string temp)
{
if (temp == hash) {
return true;
} else {
return false;
}
}

public void ClearHash ()
{
hash = "";
}

}

Client main program

using UnityEngine;
using System.Collections.Generic;

public class ClientProgram : MonoBehaviour
{
public string log;
public AsynchronousClientSocket AsynchronousClientClass;

public void OnGUI ()
{
GUILayout.BeginArea (new Rect (Screen.width / 2 - 250, Screen.height / 2 - 250, 500, 500));

GUI.TextArea (new Rect (0, 0, 500, 300), log);

if (GUI.Button (new Rect (200, 310, 100, 30), "Connect")) {
AsynchronousClientClass.StartClient ();
}

GUILayout.EndArea ();
}
}

Need help to format my code, i try many time format my code, but it keep pop up "your post appear to contain code.... even all already inside the code tab. I align all my code to left and then it work well...

i am new in unity and new in networking and security programming stuff, i hope someone can point me the better way of writing .


ouch ... my head hurts ... try something simpler like ...

http://ccoder.co.uk/files/sockets.zip

That should get you going :)

This is a subset of code from a much bigger project i have (an MMO server system for unity games). I really should finish it some time !!!