From 00211e5b5c7ed7d908b96968cf3e36baaf0fdeed Mon Sep 17 00:00:00 2001 From: "[-_-Mr_Veil-_-]" Date: Sun, 8 Aug 2021 17:35:05 +0300 Subject: [PATCH] Migrate to .NET Standard 2.0 --- src/Client.cs | 13 +++++++------ src/Encryption.cs | 14 +++++++------- src/Generator.cs | 3 ++- src/SHA.cs | 10 ++++++++++ src/Session.cs | 7 ++++--- src/WTelegramClient.csproj | 20 ++++++++++++++++---- 6 files changed, 46 insertions(+), 21 deletions(-) create mode 100644 src/SHA.cs diff --git a/src/Client.cs b/src/Client.cs index 99adaf6..4e4ddcb 100644 --- a/src/Client.cs +++ b/src/Client.cs @@ -82,7 +82,8 @@ namespace WTelegram public async Task ConnectAsync() { - var endpoint = _session.DataCenter == null ? IPEndPoint.Parse(Config("server_address")) + var serverAddress = Config("server_address").Split(':'); + var endpoint = _session.DataCenter == null ? new IPEndPoint(IPAddress.Parse(serverAddress[0]), int.Parse(serverAddress[1])) : new IPEndPoint(IPAddress.Parse(_session.DataCenter.ip_address), _session.DataCenter.port); Helpers.Log(2, $"Connecting to {endpoint}..."); _tcpClient = new TcpClient(endpoint.AddressFamily); @@ -179,7 +180,7 @@ namespace WTelegram byte[] clearBuffer = clearStream.GetBuffer(); BinaryPrimitives.WriteInt32LittleEndian(clearBuffer.AsSpan(28), clearLength - 32); // patch message_data_length RNG.GetBytes(clearBuffer, clearLength, padding); - var clearSha1 = SHA1.HashData(clearBuffer.AsSpan(0, clearLength)); // padding excluded from computation! + var clearSha1 = SHA.SHA1.ComputeHash(clearBuffer, 0, clearLength); // padding excluded from computation! byte[] encrypted_data = EncryptDecryptMessage(clearBuffer.AsSpan(0, clearLength + padding), true, _session.AuthKey, clearSha1); writer.Write(_session.AuthKeyID); // int64 auth_key_id @@ -193,10 +194,10 @@ namespace WTelegram BinaryPrimitives.WriteInt32LittleEndian(buffer, frameLength + 4); // patch frame_len with correct value uint crc = Force.Crc32.Crc32Algorithm.Compute(buffer, 0, frameLength); writer.Write(crc); // int32 frame_crc - var frame = memStream.GetBuffer().AsMemory(0, frameLength + 4); + var frame = memStream.GetBuffer()[..(frameLength + 4)]; //TODO: support Transport obfuscation? - await _networkStream.WriteAsync(frame); + await _networkStream.WriteAsync(frame, 0, frame.Length); _lastSentMsg = msg; } @@ -252,7 +253,7 @@ namespace WTelegram if ((msgId & 1) == 0) throw new ApplicationException($"Invalid server msgId {msgId}"); if ((seqno & 1) != 0) lock(_msgsToAck) _msgsToAck.Add(msgId); if (decrypted_data.Length - 32 - length is < 0 or > 15) throw new ApplicationException($"Unexpected decrypted message_data_length {length} / {decrypted_data.Length - 32}"); - if (!data.AsSpan(8, 16).SequenceEqual(SHA1.HashData(decrypted_data.AsSpan(0, 32 + length)).AsSpan(4))) + if (!data.AsSpan(8, 16).SequenceEqual(SHA.SHA1.ComputeHash(decrypted_data, 0, 32 + length).AsSpan(4))) throw new ApplicationException($"Mismatch between MsgKey & decrypted SHA1"); var ctorNb = reader.ReadUInt32(); @@ -303,7 +304,7 @@ namespace WTelegram { for (int offset = 0; offset != length;) { - var read = await stream.ReadAsync(buffer.AsMemory(offset, length - offset)); + var read = await stream.ReadAsync(buffer, offset, length - offset); if (read == 0) return offset; offset += read; } diff --git a/src/Encryption.cs b/src/Encryption.cs index 028a61d..c2639cc 100644 --- a/src/Encryption.cs +++ b/src/Encryption.cs @@ -63,7 +63,7 @@ namespace WTelegram if (answerObj is not ServerDHInnerData serverDHinnerData) throw new ApplicationException("not server_DH_inner_data"); long padding = encryptedReader.BaseStream.Length - encryptedReader.BaseStream.Position; if (padding >= 16) throw new ApplicationException("Too much pad"); - if (!Enumerable.SequenceEqual(SHA1.HashData(answer.AsSpan(20..^(int)padding)), answerHash)) + if (!Enumerable.SequenceEqual(SHA.SHA1.ComputeHash(answer, 20, answer.Length - (int)padding), answerHash)) throw new ApplicationException("Answer SHA1 mismatch"); if (serverDHinnerData.nonce != resPQ.nonce) throw new ApplicationException("Nonce mismatch"); if (serverDHinnerData.server_nonce != resPQ.server_nonce) throw new ApplicationException("Server Nonce mismatch"); @@ -92,7 +92,7 @@ namespace WTelegram var authKey = gab.ToByteArray(true, true); //8) - var authKeyHash = SHA1.HashData(authKey); + var authKeyHash = SHA.SHA1.ComputeHash(authKey); retry_id = BinaryPrimitives.ReadInt64LittleEndian(authKeyHash); // (auth_key_aux_hash) //9) reply = await client.RecvInternalAsync(); @@ -104,7 +104,7 @@ namespace WTelegram new_nonce.raw.CopyTo(expected_new_nonceN, 0); expected_new_nonceN[32] = 1; Array.Copy(authKeyHash, 0, expected_new_nonceN, 33, 8); // (auth_key_aux_hash) - if (!Enumerable.SequenceEqual(setClientDHparamsAnswer.new_nonce_hashN.raw, SHA1.HashData(expected_new_nonceN).Skip(4))) + if (!Enumerable.SequenceEqual(setClientDHparamsAnswer.new_nonce_hashN.raw, SHA.SHA1.ComputeHash(expected_new_nonceN).Skip(4))) throw new ApplicationException("setClientDHparamsAnswer.new_nonce_hashN mismatch"); session.AuthKeyID = BinaryPrimitives.ReadInt64LittleEndian(authKeyHash.AsSpan(12)); @@ -164,7 +164,7 @@ namespace WTelegram if (clearLength > 255) throw new ApplicationException("PQInnerData too big"); byte[] clearBuffer = clearStream.GetBuffer(); RNG.GetBytes(clearBuffer, clearLength, 255 - clearLength); - SHA1.HashData(clearBuffer.AsSpan(20..clearLength), clearBuffer); // patch with SHA1 + clearBuffer = SHA.SHA1.ComputeHash(clearBuffer, 20, clearLength); // patch with SHA1 var encrypted_data = BigInteger.ModPow(new BigInteger(clearBuffer, true, true), // encrypt with RSA key new BigInteger(publicKey.e, true, true), new BigInteger(publicKey.n, true, true)).ToByteArray(true, true); @@ -191,7 +191,7 @@ namespace WTelegram clearStream.SetLength(clearLength + padding); byte[] clearBuffer = clearStream.GetBuffer(); RNG.GetBytes(clearBuffer, clearLength, padding); - SHA1.HashData(clearBuffer.AsSpan(20..clearLength), clearBuffer); + clearBuffer = SHA.SHA1.ComputeHash(clearBuffer, 20, clearLength); var encrypted_data = AES_IGE_EncryptDecrypt(clearBuffer.AsSpan(0, clearLength + padding), tmp_aes_key, tmp_aes_iv, true); return new Fn.SetClientDHParams @@ -208,8 +208,8 @@ namespace WTelegram rsa.ImportFromPem(pem); var rsaParam = rsa.ExportParameters(false); var publicKey = new RSAPublicKey { n = rsaParam.Modulus, e = rsaParam.Exponent }; - var bareData = Schema.Serialize(publicKey).AsSpan(4); // bare serialization - var fingerprint = BinaryPrimitives.ReadInt64LittleEndian(SHA1.HashData(bareData).AsSpan(12)); // 64 lower-order bits of SHA1 + var bareData = Schema.Serialize(publicKey); // bare serialization + var fingerprint = BinaryPrimitives.ReadInt64LittleEndian(SHA.SHA1.ComputeHash(bareData, 4, bareData.Length - 4).AsSpan(12)); // 64 lower-order bits of SHA1 PublicKeys[fingerprint] = publicKey; Helpers.Log(1, $"Loaded a public key with fingerprint {fingerprint:X}"); } diff --git a/src/Generator.cs b/src/Generator.cs index 5bfcccb..00efc55 100644 --- a/src/Generator.cs +++ b/src/Generator.cs @@ -3,9 +3,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; -using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; +using System.Text.Json; +using System.Text.Json.Serialization; namespace WTelegram { diff --git a/src/SHA.cs b/src/SHA.cs new file mode 100644 index 0000000..ece9080 --- /dev/null +++ b/src/SHA.cs @@ -0,0 +1,10 @@ +using System.Security.Cryptography; + +namespace WTelegram +{ + internal static class SHA + { + public static SHA1 SHA1 => SHA1.Create(); + public static SHA256 SHA256 => SHA256.Create(); + } +} diff --git a/src/Session.cs b/src/Session.cs index 18fc52a..2147382 100644 --- a/src/Session.cs +++ b/src/Session.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Security.Cryptography; +using System.Text; using System.Text.Json; namespace WTelegram @@ -49,20 +50,20 @@ namespace WTelegram using var aes = Aes.Create(); using var decryptor = aes.CreateDecryptor(apiHash, input[0..16]); var utf8Json = decryptor.TransformFinalBlock(input, 16, input.Length - 16); - if (!SHA256.HashData(utf8Json.AsSpan(32)).SequenceEqual(utf8Json[0..32])) + if (!SHA.SHA256.ComputeHash(utf8Json, 32, utf8Json.Length - 32).SequenceEqual(utf8Json[0..32])) throw new ApplicationException("Integrity check failed in session loading"); return JsonSerializer.Deserialize(utf8Json.AsSpan(32), Helpers.JsonOptions); } internal void Save() { - var utf8Json = JsonSerializer.SerializeToUtf8Bytes(this, Helpers.JsonOptions); + var utf8Json = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(this, Helpers.JsonOptions)); var finalBlock = new byte[16]; var output = new byte[(16 + 32 + utf8Json.Length + 15) & ~15]; Encryption.RNG.GetBytes(output, 0, 16); using var aes = Aes.Create(); using var encryptor = aes.CreateEncryptor(_apiHash, output[0..16]); - encryptor.TransformBlock(SHA256.HashData(utf8Json), 0, 32, output, 16); + encryptor.TransformBlock(SHA.SHA256.ComputeHash(utf8Json), 0, 32, output, 16); encryptor.TransformBlock(utf8Json, 0, utf8Json.Length & ~15, output, 48); utf8Json.AsSpan(utf8Json.Length & ~15).CopyTo(finalBlock); encryptor.TransformFinalBlock(finalBlock, 0, utf8Json.Length & 15).CopyTo(output.AsMemory(48 + utf8Json.Length & ~15)); diff --git a/src/WTelegramClient.csproj b/src/WTelegramClient.csproj index 963e370..eb58d87 100644 --- a/src/WTelegramClient.csproj +++ b/src/WTelegramClient.csproj @@ -2,7 +2,8 @@ Library - net5.0 + netstandard2.0 + latest WTelegram true True @@ -10,7 +11,7 @@ snupkg true WTelegramClient - Telegram client library written 100% in C# and .NET Core + Telegram client library written 100% in C# and .NET Standard Wizou Copyright © Olivier Marcoux 2021 Telegram;Client;Api;UserBot;MTProto @@ -18,7 +19,6 @@ https://github.com/wiz0u/WTelegramClient https://github.com/wiz0u/WTelegramClient.git git - @@ -28,12 +28,24 @@ - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive +