/// <summary> /// Constructor that initializes object with encryption key /// </summary> /// <param name="key">Encyrption key for algorithm must be in valid size for cipher algorigthm</param> /// <param name="useSalt">Use random initialization vector for encryption</param> /// <param name="cipherAlgo">Algorithm used for encrytion</param> public Cipher(byte[] key, bool useSalt = false, CipherAlgo cipherAlgo = CipherAlgo.TripleDES) { Check.CheckNull(key, "Cipher(key)"); encrypto = cipherAlgo switch { CipherAlgo.TripleDES => new TripleDESCryptoServiceProvider(), CipherAlgo.AES => new AesManaged(), _ => throw new NotSupportedException(string.Format("Cipher algorithm not supported: {0}", cipherAlgo)), }; CipherAlgo = cipherAlgo; encrypto.Key = key; encrypto.Padding = PaddingMode.PKCS7; encrypto.Mode = useSalt ? CipherMode.CBC : CipherMode.ECB; }
public ClientEventArgs(Int16 packetType, bool isEncrypted, bool hasMessageAuth, CipherAlgo cipherAlgo, byte[] cipherIV, MessageAuthAlgo messageAuthAlgo, byte[] messageAuthenticationCode, byte[] data) { PacketType = packetType; IsEncrypted = isEncrypted; HasMessageAuth = hasMessageAuth; CipherAlgorithm = cipherAlgo; CipherIV = cipherIV; MessageAuthenticationAlgorithm = messageAuthAlgo; MessageAuthentication = messageAuthenticationCode; Data = data; }
/// <summary> /// Builds the encrypted message. /// </summary> /// <returns>The encrypted message.</returns> /// <param name="data">Data.</param> /// <param name="key">Key.</param> /// <param name="cipherAlgo">Algorithm used to encrypt.</param> /// <param name="algo">Algorithm ID.</param> /// <param name="iv">Iv.</param> static byte[] BuildEncryptedMessage(byte[] data, byte[] key, CipherAlgo cipherAlgo, out Int16 algo, byte[] iv = null) { switch (cipherAlgo) { case CipherAlgo.AES256: algo = 1; if (iv == null) { throw new PacketGenerationException("Invalid IV for AES256"); } return(AESCipher.EncryptData(data, key, iv)); case CipherAlgo.NOALGO: algo = -1; return(null); default: throw new PacketGenerationException("Cipher Algorithm not implemented"); } }
/// <summary> /// Constructor that initializes object with encryption key /// </summary> /// <param name="key">Encyrption key for algorithm must be in valid size for cipher algorigthm</param> /// <param name="useSalt">Use random initialization vector for encryption</param> /// <param name="cipherAlgo">Algorithm used for encrytion</param> public Cipher(byte[] key, bool useSalt=false, CipherAlgo cipherAlgo = CipherAlgo.TripleDES) { Guard.CheckNull(key, "Cipher(key)"); switch (cipherAlgo) { case CipherAlgo.TripleDES: this.encrypto = new TripleDESCryptoServiceProvider(); break; case CipherAlgo.AES: this.encrypto = new AesManaged(); break; default: throw new NotSupportedException(string.Format("Cipher algorithm not supported: {0}", cipherAlgo)); } this.CipherAlgo = cipherAlgo; this.encrypto.Key = key; this.encrypto.Padding = PaddingMode.PKCS7; this.encrypto.Mode = useSalt ? CipherMode.CBC : CipherMode.ECB; }
/// <summary> /// Constructor that initializes object with encryption key /// </summary> /// <param name="key">Encyrption key for algorithm must be in valid size for cipher algorigthm</param> /// <param name="useSalt">Use random initialization vector for encryption</param> /// <param name="cipherAlgo">Algorithm used for encrytion</param> public Cipher(byte[] key, bool useSalt = false, CipherAlgo cipherAlgo = CipherAlgo.TripleDES) { Guard.CheckNull(key, "Cipher(key)"); switch (cipherAlgo) { case CipherAlgo.TripleDES: this.encrypto = new TripleDESCryptoServiceProvider(); break; case CipherAlgo.AES: this.encrypto = new AesManaged(); break; default: throw new NotSupportedException(string.Format("Cipher algorithm not supported: {0}", cipherAlgo)); } this.CipherAlgo = cipherAlgo; this.encrypto.Key = key; this.encrypto.Padding = PaddingMode.PKCS7; this.encrypto.Mode = useSalt ? CipherMode.CBC : CipherMode.ECB; }
/// <summary> /// Starts listening for messages from the user /// </summary> void StartListening() { int requestCount = 0; requestCount = 0; while (!stop) { try { requestCount = requestCount + 1; NetworkStream stream = Socket.GetStream(); byte[] dataLength = new byte[4]; stream.Read(dataLength, 0, 4); int dLength = BitConverter.ToInt32(dataLength, 0); byte[] packetType = new byte[2]; stream.Read(packetType, 0, 2); Int16 pType = BitConverter.ToInt16(packetType, 0); byte[] isEnc = new byte[1]; stream.Read(isEnc, 0, 1); bool isEncrypted = isEnc[0] != 0b0; byte[] hasMac = new byte[1]; stream.Read(hasMac, 0, 1); bool hasMessageAuth = isEnc[0] != 0b0; Int16 cipherAlgorithm = 0; byte[] cipherIV = null; if (isEncrypted) { byte[] ciptherAlgo = new byte[2]; stream.Read(ciptherAlgo, 0, 2); cipherAlgorithm = BitConverter.ToInt16(ciptherAlgo, 0); byte[] cipherIvSize = new byte[4]; stream.Read(cipherIvSize, 0, 4); cipherIV = new byte[BitConverter.ToInt32(cipherIvSize, 0)]; stream.Read(cipherIV, 0, BitConverter.ToInt32(cipherIvSize, 0)); } CipherAlgo cAlgo = CipherAlgo.NOALGO; if (isEncrypted) { switch (cipherAlgorithm) { case 0: cAlgo = CipherAlgo.AES256; break; } } Int16 macAlgorithm = 0; byte[] msgMac = null; if (hasMessageAuth) { byte[] macAlgo = new byte[2]; stream.Read(macAlgo, 0, 2); macAlgorithm = BitConverter.ToInt16(macAlgo, 0); byte[] macSize = new byte[4]; stream.Read(macSize, 0, 4); msgMac = new byte[BitConverter.ToInt32(macSize, 0)]; stream.Read(msgMac, 0, BitConverter.ToInt32(macSize, 0)); } MessageAuthAlgo algo = MessageAuthAlgo.NOALGO; if (hasMessageAuth) { switch (macAlgorithm) { case 0: algo = MessageAuthAlgo.HMACSHA256; break; } } byte[] data = new byte[dLength]; stream.Read(data, 0, dLength); ClientEventArgs e = new ClientEventArgs(pType, isEncrypted, hasMessageAuth, cAlgo, cipherIV, algo, msgMac, data); MessageReceived(this, e); } catch (Exception) { if (!stop) { ConnectionLost(this, null); stop = true; } } } }
/// <summary> /// Starts listening for incoming connections /// </summary> /// <param name="ip">Ip.</param> /// <param name="port">Port.</param> void StartListening(IPAddress ip, int port) { TcpListener serverSocket = new TcpListener(ip, port); TcpClient clientSocket = default(TcpClient); int counter = 0; serverSocket.Start(); while (!stop) { if (serverSocket.Pending()) { counter += 1; clientSocket = serverSocket.AcceptTcpClient(); NetworkStream stream = clientSocket.GetStream(); byte[] dataLength = new byte[4]; stream.Read(dataLength, 0, 4); int dLength = BitConverter.ToInt32(dataLength, 0); byte[] packetType = new byte[2]; stream.Read(packetType, 0, 2); Int16 pType = BitConverter.ToInt16(packetType, 0); byte[] isEnc = new byte[1]; stream.Read(isEnc, 0, 1); bool isEncrypted = isEnc[0] != 0b0; byte[] hasMac = new byte[1]; stream.Read(hasMac, 0, 1); bool hasMessageAuth = isEnc[0] != 0b0; Int16 cipherAlgorithm = 0; byte[] cipherIV = null; if (isEncrypted) { byte[] ciptherAlgo = new byte[2]; stream.Read(ciptherAlgo, 0, 2); cipherAlgorithm = BitConverter.ToInt16(ciptherAlgo, 0); byte[] cipherIvSize = new byte[4]; stream.Read(cipherIvSize, 0, 4); cipherIV = new byte[BitConverter.ToInt32(cipherIvSize, 0)]; stream.Read(cipherIV, 0, BitConverter.ToInt32(cipherIvSize, 0)); } CipherAlgo cAlgo = CipherAlgo.NOALGO; if (isEncrypted) { switch (cipherAlgorithm) { case 0: cAlgo = CipherAlgo.AES256; break; } } Int16 macAlgorithm = 0; byte[] msgMac = null; if (hasMessageAuth) { byte[] macAlgo = new byte[2]; stream.Read(macAlgo, 0, 2); macAlgorithm = BitConverter.ToInt16(macAlgo, 0); byte[] macSize = new byte[4]; stream.Read(macSize, 0, 4); msgMac = new byte[BitConverter.ToInt32(macSize, 0)]; stream.Read(msgMac, 0, BitConverter.ToInt32(macSize, 0)); } MessageAuthAlgo algo = MessageAuthAlgo.NOALGO; if (hasMessageAuth) { switch (macAlgorithm) { case 0: algo = MessageAuthAlgo.HMACSHA256; break; } } byte[] data = new byte[dLength]; stream.Read(data, 0, dLength); ClientEventArgs _e = new ClientEventArgs(pType, isEncrypted, hasMessageAuth, cAlgo, cipherIV, algo, msgMac, data); ClientConnected(data, clientSocket, _e); } } /*BroadcastShutdownToClients(); * foreach (DictionaryEntry item in clientHandlers) * ((ClientHandler)item.Value).Disconnect(); * if (clientSocket != null) * clientSocket.Close(); * serverSocket.Stop();*/ }
/// <summary> /// Builds the network packet /// </summary> /// <returns>The packet.</returns> /// <param name="message">Byte array that contains the data.</param> /// <param name="cipherKey">Cipher key.</param> /// <param name="cipherIv">Cipher iv.</param> /// <param name="cipherAlgo">Cipher algo, to enable encryption change CipherAlgo to other algorithm.</param> /// <param name="messageAuthAlgoKey">Key to generate HMAC and MAC.</param> /// <param name="messageAuthAlgo">Algorithm used to create the HMAC or MAC to disable the MessageAuth use MessageAuthAlgo.NOALGO.</param> /// <param name="type">Type.</param> public static byte[] BuildPacket(byte[] message, byte[] cipherKey = null, byte[] cipherIv = null, CipherAlgo cipherAlgo = CipherAlgo.NOALGO, byte[] messageAuthAlgoKey = null, MessageAuthAlgo messageAuthAlgo = MessageAuthAlgo.NOALGO, Int16 type = -1) { if (messageAuthAlgo != MessageAuthAlgo.NOALGO) { if (messageAuthAlgoKey == null) { throw new PacketGenerationException("Missing MAC/HMAC Key"); } } if (cipherAlgo != CipherAlgo.NOALGO) { if (cipherKey == null) { throw new PacketGenerationException("Missing encryption key"); } } // packet information byte[] packetType = BitConverter.GetBytes(type); byte[] isEncrypted = new byte[1]; isEncrypted[0] = cipherAlgo != CipherAlgo.NOALGO ? (byte)0b1 : (byte)0b0; byte[] hasAuth = new byte[1]; hasAuth[0] = messageAuthAlgo != MessageAuthAlgo.NOALGO ? (byte)0b1 : (byte)0b0; byte[] macAlgo = new byte[2]; byte[] encAlgo = new byte[2]; //packet data Int16 cipherAlgoId = 0; byte[] data = (cipherAlgo != CipherAlgo.NOALGO) ? BuildEncryptedMessage(message, cipherKey, cipherAlgo, out cipherAlgoId, cipherIv) : message; Int16 msgAuthAlgo = 0; byte[] mac = (messageAuthAlgo != MessageAuthAlgo.HMACSHA256) ? BuildMessageAuthAlgo(data, messageAuthAlgo, messageAuthAlgoKey, out msgAuthAlgo) : null; // update packet information if (messageAuthAlgo != MessageAuthAlgo.NOALGO) { macAlgo = BitConverter.GetBytes(msgAuthAlgo); } if (cipherAlgo != CipherAlgo.NOALGO) { encAlgo = BitConverter.GetBytes(cipherAlgoId); } // packet size calculation int packetSize = 4; if (cipherAlgo != CipherAlgo.NOALGO) { packetSize += 6; packetSize += cipherIv != null ? cipherIv.Length : 0; } if (messageAuthAlgo != MessageAuthAlgo.NOALGO) { packetSize += 6; packetSize += mac.Length; } packetSize += data.Length; byte[] size = BitConverter.GetBytes(data.Length); byte[] packet = new byte[packetSize + 4]; // merge all information to one array Array.Copy(size, packet, 4); Array.Copy(packetType, 0, packet, 4, 2); Array.Copy(isEncrypted, 0, packet, 6, 1); Array.Copy(hasAuth, 0, packet, 7, 1); if (cipherAlgo != CipherAlgo.NOALGO) { int civl = cipherIv != null ? cipherIv.Length : 0; Array.Copy(encAlgo, 0, packet, 8, 2); Array.Copy(BitConverter.GetBytes(civl), 0, packet, 10, 4); if (cipherIv != null) { Array.Copy(cipherIv, 0, packet, 14, cipherIv.Length); } // if it also contains Message Auth if (messageAuthAlgo != MessageAuthAlgo.NOALGO) { Array.Copy(macAlgo, 0, packet, 14 + civl, 2); Array.Copy(BitConverter.GetBytes(mac.Length), 0, packet, 16 + civl, 4); Array.Copy(mac, 0, packet, 20 + civl, mac.Length); Array.Copy(data, 0, packet, 20 + civl + mac.Length, data.Length); } else { Array.Copy(data, 0, packet, 14 + civl, data.Length); } } else { if (messageAuthAlgo != MessageAuthAlgo.NOALGO) { Array.Copy(macAlgo, 0, packet, 8, 2); Array.Copy(BitConverter.GetBytes(mac.Length), 0, packet, 10, 4); Array.Copy(mac, 0, packet, 14, mac.Length); Array.Copy(data, 0, packet, 14 + mac.Length, data.Length); } else { Array.Copy(data, 0, packet, 8, data.Length); } } return(packet); }
void GetMessage() { while (IsListening) { try { serverStream = clientSocket.GetStream(); byte[] dataLength = new byte[4]; serverStream.Read(dataLength, 0, 4); int dLength = BitConverter.ToInt32(dataLength, 0); byte[] packetType = new byte[2]; serverStream.Read(packetType, 0, 2); Int16 pType = BitConverter.ToInt16(packetType, 0); byte[] isEnc = new byte[1]; serverStream.Read(isEnc, 0, 1); bool isEncrypted = isEnc[0] != 0b0; byte[] hasMac = new byte[1]; serverStream.Read(hasMac, 0, 1); bool hasMessageAuth = isEnc[0] != 0b0; Int16 cipherAlgorithm = 0; byte[] cipherIV = null; if (isEncrypted) { byte[] ciptherAlgo = new byte[2]; serverStream.Read(ciptherAlgo, 0, 2); cipherAlgorithm = BitConverter.ToInt16(ciptherAlgo, 0); byte[] cipherIvSize = new byte[4]; serverStream.Read(cipherIvSize, 0, 4); cipherIV = new byte[BitConverter.ToInt32(cipherIvSize, 0)]; serverStream.Read(cipherIV, 0, BitConverter.ToInt32(cipherIvSize, 0)); } CipherAlgo cAlgo = CipherAlgo.NOALGO; if (isEncrypted) { switch (cipherAlgorithm) { case 0: cAlgo = CipherAlgo.AES256; break; } } Int16 macAlgorithm = 0; byte[] msgMac = null; if (hasMessageAuth) { byte[] macAlgo = new byte[2]; serverStream.Read(macAlgo, 0, 2); macAlgorithm = BitConverter.ToInt16(macAlgo, 0); byte[] macSize = new byte[4]; serverStream.Read(macSize, 0, 4); msgMac = new byte[BitConverter.ToInt32(macSize, 0)]; serverStream.Read(msgMac, 0, BitConverter.ToInt32(macSize, 0)); } MessageAuthAlgo algo = MessageAuthAlgo.NOALGO; if (hasMessageAuth) { switch (macAlgorithm) { case 0: algo = MessageAuthAlgo.HMACSHA256; break; } } byte[] data = new byte[dLength]; serverStream.Read(data, 0, dLength); ClientEventArgs e = new ClientEventArgs(pType, isEncrypted, hasMessageAuth, cAlgo, cipherIV, algo, msgMac, data); if (pType == -1234) { Connected(this, e); } else { MessageReceived(this, e); } } catch (Exception) { IsListening = false; ConnectionLost(this, null); } } }