/// <summary> /// Connects the <see cref="Client"/> asynchronously to the specified TCP port on the specified host. /// </summary> /// <param name="host">The name or IP address of the host.</param> /// <param name="port">The port to connect to.</param> /// <param name="submitCryptographicData">Set to "true" to use <see cref="Aes"/> encryption for all communications.</param> /// <remarks>Using <paramref name="submitCryptographicData" /> requires the <see cref="Client"/> to have valid <see cref="CryptographicData"/> set.</remarks> /// <returns>Returns a <see cref="Task"/> that represents the asynchronous connect operation.</returns> public async Task ConnectAsync(string host, int port, bool submitCryptographicData) { await client.ConnectAsync(host, port); reader = new StreamReader(client.GetStream()); writer = new StreamWriter(client.GetStream()); if (submitCryptographicData && CryptographicData.IsValid()) { var @params = await ReadAsync <RSAParameters>(); var encrypted = CryptographyProvider.Instance.RSAEncrypt(JsonConvert.SerializeObject(CryptographicData), @params); await WriteRawAsync(encrypted); SessionId = Guid.Parse(await ReadAsync()); } OnConnected(this, new ConnectedEventArgs()); }
/// <summary> /// Writes a line of characters asynchronously to the stream. /// </summary> /// <param name="s">The string to write to the stream.</param> /// <returns>Returns a <see cref="Task"/> that represents the asynchronous write operation.</returns> /// <remarks>The written string will be encrypted if the <see cref="Client"/> has valid <see cref="CryptographicData"/>.<para>Use the <see cref="WriteRawAsync"/> function to always write data unhandled.</para></remarks> public async Task WriteAsync(string s) { if (CryptographicData == null || !CryptographicData.IsValid()) { await WriteRawAsync(s); } else { var encrypted = await CryptographyProvider.Instance.AesEncryptAsync(s, CryptographicData); var signature = CryptographyProvider.Instance.HmacCreateSignature(encrypted, CryptographicData); await writer.WriteLineAsync($"{encrypted}|{signature}"); await writer.FlushAsync(); } }
/// <summary> /// Reads a line of characters asynchronously from the stream and returns the data as a string. /// </summary> /// <returns>Returns a <see cref="Task"/> that represents the asynchronous read operation. The value of the TResult parameter contains the next line from the stream.</returns> /// <remarks>The returned string will be decrypted if the <see cref="Client"/> has valid <see cref="CryptographicData"/> and the data seems encrypted (contains a "|").<para>Use the <see cref="ReadRawAsync"/> function to always get unhandled data.</para></remarks> /// <exception cref="ClientDisconnectedException">The <see cref="Client"/> isn't connected.</exception> /// <exception cref="HmacSignatureInvalidException">The signature is invalid or the data isn't encrypted but contains a "|".</exception> public async Task <string> ReadAsync() { if (CryptographicData == null || !CryptographicData.IsValid()) { return(await ReadRawAsync()); } var data = await ReadRawAsync(); if (!data.Contains("|")) { return(data); } var encrypted = data.Split('|')[0]; var signature = data.Split('|')[1]; if (!CryptographyProvider.Instance.HmacValidateSignature(encrypted, signature, CryptographicData)) { throw new HmacSignatureInvalidException(); } return(await CryptographyProvider.Instance.AesDecryptAsync(encrypted, CryptographicData)); }