/* Sog 游戏基础库 2016 by zouwei */ using System; using System.Net; using System.Net.Sockets; using System.Collections.Generic; using System.Security.Cryptography; namespace SogClient { public enum SessionNetSelectMode { Unknow = 0, //同步select Synchronous = 1, // 异步模式 Asynchronous = 2 } /// /// Client socket. /// public abstract class ClientSession : IMessageTrans, IDisposable { public abstract void Connect(); public abstract void Reconnect(); public abstract void Update(long nowMs); protected abstract void CloseSession(); public NetSession NetSessionObj { get; protected set; } protected Socket m_socketClient; protected ClientSessionSettings m_clientSettings; protected bool m_isConnected; protected bool m_isConnecting; //windows7 上这个效率很低,执行一次 public static object m_rsaCrypto; SogFastXTEAKey m_teaKey; private ushort m_sendSeq; /// /// connected. /// public bool IsConnected { get { if (m_isConnected == false) { return false; } //如果加密需要收到key if (m_clientSettings.CryptoMessage && m_teaKey == null) { return false; } return true; } } /// /// /// public ClientSessionSettings Settings { get { return m_clientSettings; } } /// /// /// public EndPoint LocalEndPoint { get { return m_socketClient.LocalEndPoint; } } /// /// 接收到数据事件 /// public event NetEventHandler DataReceived; protected void OnDataReceived(SessionEventArgs e) { TraceLog.Trace("OnDataReceived clientsession recv data from remote {0} to local {3} SessionID {1} length {2}", e.Session.RemoteEndPoint, e.Session.SessionID, e.Message.Header.Length, e.Session.LocalEndPoint); if(m_clientSettings.CryptoMessage) { if(e.Message.Header.Type == (int)SpecialMessageType.SessionKey) { OnSessionKeyReceive(e.Message); return; } } if (DataReceived != null) { DataReceived(this, e); } } /// /// 连接成功事件 /// public event NetEventHandler Connected; protected void OnConnected(SessionEventArgs e) { TraceLog.Trace("ClientSession.OnConnected {0} success", m_clientSettings.RemoteEndPoint); //如果需要加密在收到key消息后connected if (m_clientSettings.CryptoMessage) { TraceLog.Trace("ClientSession.OnConnected need cryptomessage, so wait sessionkey message , m_clientSettings.RemoteEndPoint{0}", m_clientSettings.RemoteEndPoint); return; } if (Connected != null) { Connected(this, e); } } /// /// 连接失败事件 /// public event NetEventHandler ConnectFail; protected void OnConnectFail(SessionEventArgs e) { TraceLog.Trace("ClientSession OnConnectFail clientsession connect {0} failed", m_clientSettings.RemoteEndPoint); m_sendSeq = 0; m_isConnected = false; m_isConnecting = false; if (ConnectFail != null) { ConnectFail(this, e); } } /// /// 连接断开事件 /// public event NetEventHandler Disconnected; protected void OnDisconnected(SessionEventArgs e) { TraceLog.Trace("ClientSession.OnDisconnected clientsession connection lost {0} ", m_clientSettings.RemoteEndPoint); if (Disconnected != null) { Disconnected(this, e); } Close(); } /// /// /// /// /// public ClientSession(ClientSessionSettings settings) { m_clientSettings = settings; } public void Close() { TraceLog.Trace("ClientSession.Close remote {0}", m_clientSettings.RemoteEndPoint); //清空密钥,重新连接就需要重新请求密钥 m_teaKey = null; m_sendSeq = 0; m_isConnected = false; m_isConnecting = false; CloseSession(); } public void OnUpdateConnectedSocketError() { TraceLog.Trace("ClientSession.OnUpdateConnectedSocketError close session"); SessionEventArgs e = new SessionEventArgs(); e.Session = NetSessionObj; OnDisconnected(e); Close(); } public void ReadSocketReadable() { NetSessionObj.RecvReadableSocket(); var dataList = NetSessionObj.GetReceivedDataQueue(); foreach (MessageData message in dataList) { TraceLog.Trace("ClientSession.ReadSocketReadable "); SessionEventArgs e = new SessionEventArgs(); e.Message = message; e.Session = NetSessionObj; //加密的消息需要解密 if (m_clientSettings.CryptoMessage && m_teaKey != null && message.Data != null && message.Data.Length > 0) { try { SogFastXTEA.Decrypt(message.Data, m_teaKey); } catch (Exception ex) { //解密失败 TraceLog.Exception(ex); continue; } } OnDataReceived(e); } dataList.Clear(); //说明接受数据出错了 if (NetSessionObj.IsSocketClosed) { OnUpdateConnectedSocketError(); return; } } protected void ConnectSucc() { m_isConnected = true; m_isConnecting = false; NetSessionObj.Bind(m_socketClient); NetSessionObj.LastDataTime = DateTime.Now; NetSessionObj.WriteSendRecvLog = true; if(m_clientSettings.CryptoMessage) { SendPublicKeyToRemote(); } } private byte[] GenSessionkeyTest(Random rand) { byte[] sessionkey = new byte[16]; byte[] val = new byte[64]; // generate data of random length int t1 = 16; while (t1 == 0) t1 = (int)(rand.NextDouble() * 65); bool done = false; while (!done) { for (int i = 0; i < 64; i++) { if (i < t1) { val[i] = (byte)(rand.NextDouble() * 256); while (val[i] == 0) val[i] = (byte)(rand.NextDouble() * 256); } else { val[i] = 0; } if (val[i] != 0) done = true; } } while (val[0] == 0) val[0] = (byte)(rand.NextDouble() * 256); Array.Copy(val, sessionkey, 16); return sessionkey; } private void SendPublicKeyToRemote() { RSAParameters rp; rp.Modulus = null; rp.Exponent = null; lock (m_rsaCrypto) { //RSABigIntegerUtils.GenRSAKey(); // TraceLog.Trace("clientsession ImportParameters "); #if false int iErrorNum = 0; int i = 0; byte[] sessionkey = null; byte[] ensessionkey = null; byte[] desessionkey = null; Random rand = new Random(); //test for(; i<100000; i++) { RSABigIntegerUtils.GenRSAKey(); sessionkey = GenSessionkeyTest(rand); ensessionkey = RSABigIntegerUtils.EncryptBytesPublic(sessionkey); desessionkey = RSABigIntegerUtils.DecryptBytesPrivite(ensessionkey); if(sessionkey.Length != desessionkey.Length) { iErrorNum++; break; } for(int j = 0; j 0) { break; } rp = RSABigIntegerUtils.GetRSAParameters(); BigInteger bi_n = new BigInteger(rp.Modulus); BigInteger bi_e = new BigInteger(rp.Exponent); BigInteger biText = new BigInteger(sessionkey); BigInteger biEnText = biText.modPow(bi_e, bi_n); byte[] outbytes = biEnText.getBytes(); if (ensessionkey.Length != outbytes.Length) { iErrorNum++; break; } for (int j = 0; j < outbytes.Length; j++) { if (outbytes[j] != ensessionkey[j]) { iErrorNum++; break; } } if (iErrorNum > 0) { break; } Console.WriteLine("test EncryptBytesPublic rsa success index {0} ", i); } if(iErrorNum > 0) { string strSessionKey = RSABigIntegerUtils.ToHexString(sessionkey); string newensessionkey = RSABigIntegerUtils.EncryptStringPublic(strSessionKey); string newdesessionkey = RSABigIntegerUtils.DecryptStringPrivite(newensessionkey); if(strSessionKey != newdesessionkey) { Console.Write("Error"); } RSABigIntegerUtils.CheckError(sessionkey); } #endif } rp = RSABigIntegerUtils.GetRSAParameters(); //清空一下,保证逻辑 m_teaKey = null; //string publickey = m_rsaCrypto.ToXmlString(false); MessageData message = new MessageData(); message.Data = null; message.Header.Type = (int)SpecialMessageType.PublicKey; //RSAParameters rp; lock (m_rsaCrypto) { //rp = m_rsaCrypto.ExportParameters(false); //rp = RSABigIntegerUtils.GenRSAKey(); } byte[] data = new byte[2 + rp.Modulus.Length + rp.Exponent.Length]; //string modulus = Convert.ToBase64String(rp.Modulus); //string exp = Convert.ToBase64String(rp.Exponent); byte[] modLenByte = BitConverter.GetBytes((Int16)rp.Modulus.Length); Buffer.BlockCopy(modLenByte, 0, data, 0, 2); Buffer.BlockCopy(rp.Modulus, 0, data, 2, rp.Modulus.Length); Buffer.BlockCopy(rp.Exponent, 0, data, 2 + rp.Modulus.Length, rp.Exponent.Length); message.Data = data; message.Header.Length = data.Length; // debug if (NetSessionObj is UdpSession udpsession) { TraceLog.Trace("ClientSession.SendPublicKeyToRemote {0} conv {1} keylen {2}" , udpsession.GetKcpName(), udpsession.GetKcpConvId(), data.Length); } else { TraceLog.Trace("ClientSession.SendPublicKeyToRemote keylen {0}", data.Length); } Send(message); } private void OnSessionKeyReceive(MessageData message) { if (m_rsaCrypto == null) { return; } byte[] keyBytes; lock (m_rsaCrypto) { keyBytes = RSABigIntegerUtils.DecryptBytesPrivite(message.Data); } if (keyBytes.Length != 16) { var aa = (UdpClientSession)this; var cc = aa.udpSession.GetKcpConvId(); TraceLog.Error("keyBytes.Length != 16 {0} {1}", aa.udpSession.GetKcpName(), cc); } m_teaKey = new SogFastXTEAKey(keyBytes); TraceLog.Trace("ClientSession.OnSessionKeyReceive decrypt session success "); SessionEventArgs e = new SessionEventArgs(); e.Session = NetSessionObj; OnConnected(e); } public void Send(NetSession socket, MessageData message) { if(m_teaKey != null && message.Data != null && message.Data.Length > 0) { SogFastXTEA.Encrypt(message.Data, m_teaKey); } m_sendSeq++; ushort crcValue = 0; if (message.Data != null && message.Data.Length > 0) { crcValue = CRC.CRC16(message.Data, message.Data.Length); } message.Header.ServerID = ((uint)m_sendSeq << 16) + crcValue; socket.SendMessageToQueue(message); } public void Send(MessageData message) { if (m_teaKey != null && message.Data != null && message.Data.Length > 0) { SogFastXTEA.Encrypt(message.Data, m_teaKey); } m_sendSeq++; ushort crcValue = 0; if(message.Data != null && message.Data.Length > 0) { crcValue = CRC.CRC16(message.Data, message.Data.Length); } message.Header.ServerID = ((uint)m_sendSeq << 16) + crcValue; NetSessionObj.SendMessageToQueue(message); } /// /// /// public void Dispose() { Close(); } } }