Migrate to .NET Standard 2.0

This commit is contained in:
[-_-Mr_Veil-_-] 2021-08-08 17:35:05 +03:00
parent 8ae3c2a283
commit 00211e5b5c
6 changed files with 46 additions and 21 deletions

View file

@ -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;
}

View file

@ -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}");
}

View file

@ -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
{

10
src/SHA.cs Normal file
View file

@ -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();
}
}

View file

@ -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<Session>(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));

View file

@ -2,7 +2,8 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<RootNamespace>WTelegram</RootNamespace>
<Deterministic>true</Deterministic>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
@ -10,7 +11,7 @@
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageId>WTelegramClient</PackageId>
<Description>Telegram client library written 100% in C# and .NET Core</Description>
<Description>Telegram client library written 100% in C# and .NET Standard</Description>
<Authors>Wizou</Authors>
<Copyright>Copyright © Olivier Marcoux 2021</Copyright>
<PackageTags>Telegram;Client;Api;UserBot;MTProto</PackageTags>
@ -18,7 +19,6 @@
<PackageProjectUrl>https://github.com/wiz0u/WTelegramClient</PackageProjectUrl>
<RepositoryUrl>https://github.com/wiz0u/WTelegramClient.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<!--<PackageReadmeFile>README.md</PackageReadmeFile> see https://github.com/NuGet/Home/issues/10791 -->
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -28,12 +28,24 @@
<ItemGroup>
<None Remove=".gitattributes" />
<None Remove=".gitignore" />
<!--<None Include="..\README.md" Pack="true" PackagePath=""/>-->
<None Remove="azure-pipelines.yml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ArrayDeconstructors.Source" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Crc32.NET" Version="1.2.0" />
<PackageReference Include="IndexRange" Version="1.0.0" />
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="TA.System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray" Version="1.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>